import os
from collections import OrderedDict

import cv2
from scipy.spatial import distance as dist

import dlib
import numpy as np
from torch import tensor

FACIAL_LANDMARKS_68_IDXS = OrderedDict([
    ("mouth", (48, 68)),
    ("right_eyebrow", (17, 22)),
    ("left_eyebrow", (22, 27)),
    ("right_eye", (36, 42)),
    ("left_eye", (42, 48)),
    ("nose", (27, 36)),
    ("jaw", (0, 17))
])

# 分别取两个眼睛区域
(lStart, lEnd) = FACIAL_LANDMARKS_68_IDXS["left_eye"]
(rStart, rEnd) = FACIAL_LANDMARKS_68_IDXS["right_eye"]


class DlibUtils:
    def __init__(self):
        self.detector = dlib.get_frontal_face_detector()
        self.predictor = dlib.shape_predictor(f"{os.getcwd()}/models/shape_predictor_68_face_landmarks.dat")
        # 设置判断参数
        self.EYE_AR_THRESH = 0.3
        self.EYE_AR_CONSEC_FRAMES = 3

    def eye_aspect_ratio(self, eye):
        # 计算距离，竖直的
        A = dist.euclidean(eye[1], eye[5])
        B = dist.euclidean(eye[2], eye[4])
        # 计算距离，水平的
        C = dist.euclidean(eye[0], eye[3])
        # ear值
        ear = (A + B) / (2.0 * C)
        return ear

    def shape_to_np(self, shape, x=0, y=0, dtype="int"):
        # 创建68*2
        coords = np.zeros((shape.num_parts, 2), dtype=dtype)
        # 遍历每一个关键点
        # 得到坐标
        for i in range(0, shape.num_parts):
            coords[i] = (shape.part(i).x + x, shape.part(i).y + y)
        return coords

    # 传入图片中含有人脸的切片，获取脸部关键点坐标
    # 输入：图片切片，x偏移量，y偏移量
    def detect_facial_landmarks(self, facial_list, imgClip, offset_x, offset_y):
        # 使用dlib的68个关键点检测器检测人脸 ,应注意坐标系的转换
        gray = cv2.cvtColor(imgClip, cv2.COLOR_BGR2GRAY)
        # 将某个人脸画面提取出来检测
        rects = self.detector(gray, 0)
        if len(rects) != 0:
            for rect in rects:
                shape = self.predictor(gray, rect)
                shape = self.shape_to_np(shape, x=offset_x, y=offset_y)
                # 计算眼睛的ear值
                leftEye = shape[lStart:lEnd]
                rightEye = shape[rStart:rEnd]
                print(dist.euclidean(leftEye[0], leftEye[3]))
                # 计算眼睛的平均间距值
                leftEAR = self.eye_aspect_ratio(leftEye)
                rightEAR = self.eye_aspect_ratio(rightEye)
                # 表示长宽比
                ear = (leftEAR + rightEAR) / 2.0
                # 绘制眼睛区域
                leftEyeHull = cv2.convexHull(leftEye)
                rightEyeHull = cv2.convexHull(rightEye)
                # 加入区域判断
                facial_list.append([ear, leftEyeHull, rightEyeHull])
                return [ear, leftEyeHull, rightEyeHull]
        else:
            return None

def openCVRectToDlib(rect: tensor):
    box = rect.tolist()
    return dlib.rectangle(int(box[0]), int(box[1]), int(box[2]), int(box[3]))
